package jmine.tec.proxy.builder;

import java.util.List;

import jmine.tec.proxy.chain.ChainElement;

/**
 * Utility class to build proxies.
 * @author takeshi
 */
public final class ProxyBuilder {

    private static final ProxyBuilderFactory FACTORY = ProxyBuilderProvider.selectProxyBuilderFactory();

    private final jmine.tec.proxy.ProxyBuilder delegate = FACTORY.newProxyBuilder();

    /**
     * Implementacao do padrao Builder. Seta o campo interfaces
     * @param ifs {@link List} o novo valor para o campo
     */
    public void setInterfaces(final List<Class<?>> ifs) {
        delegate.setInterfaces(ifs.toArray(new Class<?>[ifs.size()]));
    }

    /**
     * Implementacao do padrao Builder. Seta o campo delegate e devolve 'this'
     * @param del {@link Object} o novo valor para o campo
     */
    public void setDelegate(final Object del) {
        delegate.setDelegate(del);
    }

    /**
     * 
     */
    public ProxyBuilder() {
    }

    /**
     * Builds the proxy
     * @return Object
     */
    public Object build() {
        return delegate.build();
    }

    /**
     * @param type the type
     */
    public void setType(Class<?> type) {
        this.delegate.setMainType(type);
    }

    /**
     * Creates a proxy over a delegate (may be <code>null</code>) that implements (or extends) the given type and
     * uses the given chain elements.
     * <p>
     * If the given chain elements is empty, will return the delegate itself.
     * @param <T> the generic type
     * @param delegate the delegate
     * @param type the type
     * @param chainElements the chainElements
     * @return T
     */
    public static <T> T proxyFor(final T delegate, final Class<? extends T> type, final ChainElement... chainElements) {
        if (type == null || chainElements == null) {
            throw new NullPointerException();
        }
        if (chainElements.length == 0) {
            return delegate;
        }
        jmine.tec.proxy.ProxyBuilder builder = FACTORY.newProxyBuilder();
        builder.setMainType(type);
        builder.setDelegate(delegate);
        builder.setChainElements(chainElements);
        return type.cast(builder.build());
    }

    /**
     * @param chainElements the chainElements to set
     */
    public void setChainElements(final List<ChainElement> chainElements) {
        this.delegate.setChainElements(chainElements.toArray(new ChainElement[chainElements.size()]));
    }

}
